#include "StdAfx.h"
#include "ZoneAgent.h"
#include "Gateway.h"
#include "World/G2ZProtocol.h"
#include "ClientAgent.h"

XZoneAgent* g_pZoneAgent = NULL;

#define REGISTER_Z2G_PROTOCOL(Protocol, Func, DataStruct)       \
    do                                                          \
    {                                                           \
        m_PakProcessor[Protocol]    = &XZoneAgent::Func;        \
        m_uPakSize[Protocol]        = sizeof(DataStruct);       \
    } while (false)

XZoneAgent::XZoneAgent(void)
{
    m_dwNextPingTime    = 0;
    m_piSocketMgr       = NULL;
    m_pSocket           = NULL;

    memset(m_PakProcessor, 0, sizeof(m_PakProcessor));
    memset(m_uPakSize, 0, sizeof(m_uPakSize));

    REGISTER_Z2G_PROTOCOL(z2g_login_respond, OnPlayerLoginRespond, sizeof(Z2G_LOGIN_RESPOND));
    REGISTER_Z2G_PROTOCOL(z2g_sync_login_info, OnSyncLoginInfo, sizeof(Z2G_SYNC_LOGIN_INFO));
}

XZoneAgent::~XZoneAgent(void)
{
    Clear();
}

BOOL XZoneAgent::Setup(ISocketMgr* piSocketMgr)
{
    BOOL      bResult   = false;
    XSocket*  pSocket   = NULL;

    piSocketMgr->AddRef();
    m_piSocketMgr = piSocketMgr;

    pSocket = m_piSocketMgr->Connect(
        "172.16.11.168",
        7555,
        300, 1024 * 32, 1024 * 1024 * 8
        );
    XYLOG_FAILED_JUMP(pSocket);

    m_piSocketMgr->SetStreamDataCallback(pSocket, DataCallbackFunc);
    m_piSocketMgr->SetStreamErrorCallback(pSocket, ErrorCallbackFunc);
    m_piSocketMgr->SetSendBufferSize(pSocket, 1024 * 1024 * 8);

    m_pSocket = pSocket;

    bResult = true;
Exit0:
    Log(
        eLogInfo, "Connect to ZoneCenter %s:%d ... ... [%s]", "127.0.0.1", 7555, bResult ? "OK" : "Failed");
    return bResult;
}

void XZoneAgent::Clear()
{
    if (m_piSocketMgr && m_pSocket)
    {
        m_piSocketMgr->CloseSocket(m_pSocket);
        m_pSocket = NULL;
    }
    XY_COM_RELEASE(m_piSocketMgr);
}

void XZoneAgent::Activate()
{
    DWORD dwNowTime = XY_GetTickCount();

    if (dwNowTime > m_dwNextPingTime)
    {
        DoPingSignal();
        m_dwNextPingTime = dwNowTime + 1000;
    }
}

void XZoneAgent::Send(void* pvData, size_t uDataLen)
{
    if (m_pSocket)
    {
        m_piSocketMgr->Send(m_pSocket, pvData, uDataLen);
    }
}

void XZoneAgent::ErrorCallbackFunc(XSocket* pSocket, void* pvUsrData, int nSysErr, int nUsrErr)
{
    g_pZoneAgent->ProcessSocketError(pSocket, pvUsrData, nSysErr, nUsrErr);
}

void XZoneAgent::DataCallbackFunc(XSocket* pSocket, void* pvUsrData, BYTE* pbyData, size_t uDataLen)
{
    g_pZoneAgent->ProcessReceivePackage(pSocket, pvUsrData, pbyData, uDataLen);
}

void XZoneAgent::ProcessSocketError(XSocket* pSocket, void* pvUsrData, int nSysErr, int nUsrErr)
{
    assert(pSocket == m_pSocket);

    Log(eLogError, "[ZoneAgent] Connection lost, SysErr = %d, UsrErr = %d", nSysErr, nUsrErr);

    g_pGateway->Quit();

    m_piSocketMgr->CloseSocket(m_pSocket);
    m_pSocket = NULL;
}

void XZoneAgent::ProcessReceivePackage(XSocket* pSocket, void* pvUsrData, BYTE* pbyData, size_t uDataLen)
{
    XZ2G_PROTOCOL_FUNC      pProtocolFunc       = NULL;
    XZ2GHeader*             pHeader             = NULL;

    assert(pSocket == m_pSocket);

    XYLOG_FAILED_JUMP(uDataLen >= sizeof(XZ2GHeader));

    pHeader = (XZ2GHeader*)pbyData;
    XYLOG_FAILED_JUMP(pHeader->byProtocol < z2g_protocol_total) ;

    XYLOG_FAILED_JUMP(uDataLen >= m_uPakSize[pHeader->byProtocol]);

    pProtocolFunc = m_PakProcessor[pHeader->byProtocol];
    XYLOG_FAILED_JUMP(pProtocolFunc);

    (this->*pProtocolFunc)(pbyData, uDataLen);

Exit0:
    return;
}

void XZoneAgent::DoPingSignal()
{
    G2Z_PING_SIGNAL PingPak;

    PingPak.byProtocol = g2z_ping_signal;

    Send(&PingPak, sizeof(PingPak));
}

void XZoneAgent::DoPlayerLoginRequest(XPlayerAgent* pPlayer)
{
    G2Z_LOGIN_REQUEST Request;

    assert(pPlayer);

    Request.byProtocol = g2z_login_request;
    SafeCopyString(Request.szAccount, pPlayer->szAccount);

    Send(&Request, sizeof(Request));
}

void XZoneAgent::OnPlayerLoginRespond(BYTE* pbyData, size_t uDataLen)
{
    Z2G_LOGIN_RESPOND*  pRespond    = (Z2G_LOGIN_RESPOND*)pbyData;
    XPlayerAgent*       pPlayer     = g_pClientAgent->GetPlayer(pRespond->nLoginID);

    XYLOG_FAILED_JUMP(pPlayer);

    g_pClientAgent->DoAccountLoginRespond(pPlayer, (int)pRespond->byResult);

Exit0:
    return;
}

void XZoneAgent::OnSyncLoginInfo(BYTE* pbyData, size_t uDataLen)
{
    Z2G_SYNC_LOGIN_INFO*    pInfo   = (Z2G_SYNC_LOGIN_INFO*)pbyData;
    XPlayerAgent*           pPlayer = g_pClientAgent->GetPlayer(pInfo->nLoginID);

    XYLOG_FAILED_JUMP(pPlayer);

    g_pClientAgent->DoSyncLoginInfo(pPlayer, pInfo->szIP, pInfo->nPort);

Exit0:
    return;
}


